
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using Swaf.Logging;
using System.Threading;

namespace Swaf
{
    /// <summary>
    /// Defines the root exeception for all other exceptions defined in the framework
    /// </summary>
    [Serializable]
    public class BaseException : ApplicationException
    {
        #region Static Members

        protected static int s_exceptionTraceLevel = 0;
        protected static int s_defaultLogLevel = 0;
        protected static ILog s_log = null;
        protected static ITrace s_trace = null;
        protected static IAudit s_audit = null;
        protected static Boolean s_logExceptions = false;

        #endregion

        #region Static Methods

        public static void defineLog(ILog l) { s_log = l; }
        public static void defineTrace(ITrace t) { s_trace = t; }
        public static void defineAudit(IAudit a) { s_audit = a; }

        public static void suppressLogging(Boolean suppress)
        {
            LocalDataStoreSlot slot = Thread.GetNamedDataSlot("suppressLogging");
            Thread.SetData(slot, suppress);
        }

        public static Boolean isLoggingSuppressed()
        {
            LocalDataStoreSlot slot = Thread.GetNamedDataSlot("suppressLogging");
            Object supData = Thread.GetData(slot);

            // If supData is not null and set to "true" then return true
            return (supData != null && (((Boolean)supData) == true));
        }

        #endregion

        #region Static Properties

        public static int ExceptionTraceLevel
        {
            get { return s_exceptionTraceLevel; }
            set { s_exceptionTraceLevel = value; }
        }

        public static int DefaultLogLevel
        {
            get { return s_defaultLogLevel; }
            set { s_defaultLogLevel = value; }
        }

        public static Boolean LogExceptions
        {
            get { return s_logExceptions; }
            set { s_logExceptions = value; }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Default exception constructor that provides no detail other then the class type of
        /// the exception itself.
        /// </summary>
        public BaseException()
        {
            writeTraceEntry();
            writeLogEntry();
        }

        public BaseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
        {
            writeTraceEntry();
            writeLogEntry();
        }

        /// <summary>
        /// Simple text message constructor that maps to System.Exception message.
        /// </summary>
        /// <param name="msg">Passed to Exception.Message</param>
        public BaseException(string msg)
            : base(msg) //TODO: Call resmgr.resolve on this
        {
            writeTraceEntry();
            writeLogEntry();
        }

        /// <summary>
        /// Creates exception with an 'inner exception' as specified.  This helps to pass detailed
        /// exception info when rethrowing with a new exception.
        /// </summary>
        /// <param name="msg">Base description of exception - passed to Exception.Message</param>
        /// <param name="innerException">The root cause of this exception - passed to Exception.InnerException</param>
        public BaseException(string msg, Exception innerException)
            : base(msg, innerException)
        {
            writeTraceEntry();
            writeLogEntry();
        }

        #endregion

        #region Log Methods

        protected void writeLogEntry()
        {
            if (LogExceptions && !isLoggingSuppressed())
                writeLog();
        }

        public virtual void writeLog()
        {
            writeLog(s_defaultLogLevel, getFullExceptionString(this));
        }

        public virtual void writeLog(int logLevel)
        {
            writeLog(logLevel, getFullExceptionString(this));
        }

        public virtual void writeLog(string additionalInfo, params object[] changes)
        {
            writeLog(s_defaultLogLevel, getFullExceptionString(this));
        }

        public virtual void writeLog(int logLevel, string additionalInfo, params object[] changes)
        {
            if (s_log != null)
                s_log.println(logLevel, additionalInfo, changes);
        }

        #endregion

        #region Audit Methods

        public virtual void writeAudit(string eventId, string additionalData)
        {
            s_audit.write(eventId, getFullExceptionString(this), additionalData);
        }

        private void writeTraceEntry()
        {
            if (s_trace != null && !isLoggingSuppressed())
                s_trace.write(ExceptionTraceLevel, "Exception created: {0}", getFullExceptionString(this));
        }

        #endregion

		public string FullExceptionString
		{
			get
			{
				return getFullExceptionString(this);
			}
		}

		private string getFullExceptionString(Exception e)
		{
            if (e == null) return String.Empty;
				return string.Format("{0}:{1}\n		{2}", e.GetType().FullName, e.Message, getFullExceptionString(e.InnerException));
		}
    }
}
